﻿#if ENABLE_EXCEL_COM
#if ENABLE_ET_COM
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using System.Xml;
using System.Text;
using System.Diagnostics;


namespace suite_condfmt_smoke
{
    struct CondFmtData
    {
        public object StrFmla1;
        public object StrFmla2;
        public object StrStyle;
        public object CondFmtType;
        public object CondFmtOp;
    }

    class CondfmtTest: suit_base.SuiteBase
    {
        public CondfmtTest()
        {
            m_MissingValue = System.Reflection.Missing.Value;
            m_StrFmlas = new ArrayList();
            m_StrFmlas.Add("100");
            m_StrFmlas.Add("200");

            m_CondFmtData = new CondFmtData[m_CntFmtCondLimit];

            m_StrStyles = new ArrayList();
            m_StrStyles.Add("Currency");

            LoadConfig();
        }

        public override string GetCommand()
        {
            return ET_Improve.Global.CMD_CONDFMT_SMOKE;
        }

        public override void Call()
        {
            etOp.EtOp.ReRegisterET(Path.GetDirectoryName(m_StrExePath));
            tool.LogTool.GetInstance().BeginUseLog(null, "condfmtsmoke");

            Reset(1);
            Process_CellValue();
            Process_Expression();
            if (m_IdxCurFmtCond != 0)
            {
                Process_Check();
            }
            AppQuit();

            tool.Output.DumpWriteLine("Process OK!");
            tool.LogTool.GetInstance().EndUseLog();
        }

        ET.Range RangeFromApp(ET.Application etApp, int iItemSheet)
        {
            ET._Workbook workBook = m_EtApp.Workbooks.get_Item(1);
            ET._Worksheet workSheet = (ET._Worksheet)workBook.Worksheets.get_Item(iItemSheet);
            return workSheet.get_Range("A1", "IV65536");
        }

        private void AppQuit()
        {
            m_EtApp.Quit();
            try
            {Marshal.ReleaseComObject(m_EtApp);}
            catch
            { }
            finally
            { m_EtApp = null; }
        }

        void Reset(int i)
        {
            if (m_EtApp != null)
            {
                AppQuit();
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }

            m_IdxCurFmtCond = 0;
            m_CntFmtCondSet = i;

            m_EtApp = new ET.Application();
            m_EtApp.Visible = false;
            m_EtApp.DisplayAlerts = false;
            if (m_EtApp.Workbooks.Count == 0)
            {
                m_EtApp.Workbooks.Add(m_MissingValue);
            }
            if (m_EtApp.Workbooks.get_Item(1).Worksheets.Count <= 1)
            {
                m_EtApp.Workbooks.get_Item(1).Worksheets.Add(
                    m_MissingValue, 1, 1, m_MissingValue);
            }

            m_rg = RangeFromApp(m_EtApp, 1);
        }

        private void Process_CellValue()
        {
            Process_TwoFmla(ET.ETFormatConditionType.etCellValue,
                ET.ETFormatConditionOperator.etBetween);
            Process_TwoFmla(ET.ETFormatConditionType.etCellValue,
                ET.ETFormatConditionOperator.etNotBetween);

            ET.ETFormatConditionOperator[] opArray = {
                ET.ETFormatConditionOperator.etEqual,
                ET.ETFormatConditionOperator.etNotEqual,
                ET.ETFormatConditionOperator.etGreater,
                ET.ETFormatConditionOperator.etLess,
                ET.ETFormatConditionOperator.etGreaterEqual,
                ET.ETFormatConditionOperator.etLessEqual
                                                 };
            foreach (ET.ETFormatConditionOperator opx in opArray)
            {
                Process_OneFmla(ET.ETFormatConditionType.etCellValue, opx);
            }
        }

        private void Process_Expression()
        {
            Process_OneFmla(ET.ETFormatConditionType.etExpression, 0);
        }

        private void Process_OneFmla(ET.ETFormatConditionType condType, 
            object condOp)
        {
            foreach (object strFmla in m_StrFmlas)
            {
                foreach(object strStyle in m_StrStyles)
                {
                    Process_Inner(condType, condOp, strFmla, m_MissingValue, strStyle);
                }
            }
        }

        private void Process_TwoFmla(ET.ETFormatConditionType condType,
            ET.ETFormatConditionOperator condOp)
        {
            foreach (object strStyle in m_StrStyles)
            {
                foreach (object strFmla1 in m_StrFmlas)
                {
                    foreach (object strFmla2 in m_StrFmlas)
                    {
                        Process_Inner(condType, condOp, strFmla1, strFmla2, strStyle);
                    }
                }
            }
        }

        private void Process_Inner(ET.ETFormatConditionType condType,
            object condOp, object strFmla1, object strFmla2, object strStyle)
        {
            if (m_IdxCurFmtCond >= m_CntFmtCondSet)
            {
                throw new Exception("m_CurFmtCond >= m_CntLimit");
            }

            m_CondFmtData[m_IdxCurFmtCond].StrFmla1 = strFmla1;
            m_CondFmtData[m_IdxCurFmtCond].StrFmla2 = strFmla2;
            m_CondFmtData[m_IdxCurFmtCond].CondFmtOp = condOp;
            m_CondFmtData[m_IdxCurFmtCond].CondFmtType = condType;
            m_CondFmtData[m_IdxCurFmtCond].StrStyle = strStyle;

            m_rg.FormatConditions.Add(condType, condOp, strFmla1, strFmla2, strStyle);

            if (++m_IdxCurFmtCond == m_CntFmtCondSet)
            {
                Process_Check();
                Reset((m_CntFmtCondSet + 1) % m_CntFmtCondLimit + 1);
            }
        }

        private void Process_Check()
        {
            try
            {
                Console.Write("Check ");
                Process_CopyPast();
                Process_SaveOpen();
                tool.Output.DumpWriteLine("OK!");
            }
            catch (System.Exception ex)
            {
                tool.LogTool.GetInstance().AddLog(
                    tool.LogTool.LOG_TYPE.MESSAGE, null, ex.ToString(), null);
            }
        }

        private void Process_CopyPast()
        {
            m_rg.Copy(m_MissingValue);
            ET.Range rgDst = RangeFromApp(m_EtApp, 2);
            rgDst.PasteSpecial(ET.ETPasteType.etPasteAll,
                ET.ETPasteSpecialOperation.etPasteSpecialOperationNone,
                m_MissingValue, m_MissingValue);

            Process_Compare(rgDst.FormatConditions, "Copy Paste");
        }

        private void Process_SaveOpen()
        {
            m_EtApp.Workbooks.get_Item(1).SaveAs(
                m_StrTmpPath, m_MissingValue, m_MissingValue,
                m_MissingValue, m_MissingValue, false,
                ET.ETSaveAsAccessMode.etExclusive, false,
                m_MissingValue, m_MissingValue, m_MissingValue);

            m_EtApp.Workbooks.get_Item(1).Close(false, null, null);
            Debug.Assert(m_EtApp.Workbooks.Count == 0);

            m_EtApp.Workbooks.Add(m_StrTmpPath);
            m_rg = RangeFromApp(m_EtApp, 1);
            Process_Compare(m_rg.FormatConditions, "SaveOpen");
        }

        private void Process_Compare(ET.FormatConditions fmtConds, String strAction)
        {
            if (fmtConds.Count != m_CntFmtCondSet)
            {
                throw new Exception(strAction + " Count Error.");
            }

            for (int i = 0; i < m_CntFmtCondSet; ++i)
            {
                String strError = "Error: " + strAction + " " + i + " ";
                ET.FormatCondition fmtCond = fmtConds.Item(i + 1);
                if (!CompareStr(m_CondFmtData[i].StrFmla1, fmtCond.Formula1))
                {
                    throw new Exception(strError + "Fmla1");
                }
                
                if (!CompareStr(m_CondFmtData[i].StrFmla2, fmtCond.Formula2))
                {
                    throw new Exception(strError + "Fmla2");
                }

                if (fmtCond.Type != (Int32)m_CondFmtData[i].CondFmtType)
                {
                    throw new Exception(strError + "Type");
                }

                if ((ET.ETFormatConditionType)m_CondFmtData[i].CondFmtType != ET.ETFormatConditionType.etExpression)
                {
                    bool b1 = (fmtCond.Operator != (Int32)KSO.ksoSuspensive.ksoSuspensiveLong);
                    bool b2 = (m_CondFmtData[i].CondFmtOp is ET.ETFormatConditionOperator);
                    if (b1 != b2 || b1 && b2 && fmtCond.Operator != (Int32)m_CondFmtData[i].CondFmtOp)
                    {
                        throw new Exception(strError + "Operater");
                    }
                }

                ET.Style etStyle = fmtCond.Style;
                if (etStyle.Name.ToLower() != ((String)m_CondFmtData[i].StrStyle).ToLower())
                {
                    throw new Exception(strError + "Style");
                }
            }
        }

        private Boolean CompareStr(object strLhs, object strRhs)
        {
            if ((strLhs is String) || (strRhs is String))
            {
                if (!(strLhs is String) || !(strRhs is String))
                {
                    return false;
                }

                if ((String)strLhs == (String)strRhs)
                {
                    return true;
                }
                else if (((String)strLhs)[0] == '=')
                {
                    return ((String)strLhs).Substring(1) == ((String)strRhs);
                }
                else if (((String)strRhs)[0] == '=')
                {
                    return ((String)strRhs).Substring(1) == ((String)strLhs);
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return true;
            }
        }

        private void LoadConfig()
        {
            XmlNodeList xnl = tool.ConfigReader.GetElementList(
                "format-condition-smoke");
            foreach (XmlNode eleX in xnl)
            {
                if (eleX.NodeType != XmlNodeType.Element)
                {
                    continue;
                }
                XmlElement ele = (XmlElement)eleX;
                if (ele.Name == "style")
                {
                    m_StrStyles.Add(ele.GetAttribute("name"));
                }
                else if (ele.Name == "formula")
                {
                    XmlText contentXml = (XmlText)(ele.FirstChild);
                    m_StrFmlas.Add(contentXml.Value);
                }
                else if (ele.Name == "config")
                {
                    m_StrTmpPath = ele.GetAttribute("temp-save-path");
                    m_StrLogPath = ele.GetAttribute("log-path");
                    m_StrExePath = ele.GetAttribute("et-path");
                }
            }
        }

        //config
        private readonly object m_MissingValue;
        private ArrayList m_StrFmlas;
        private ArrayList m_StrStyles;
        private String m_StrTmpPath;
        private String m_StrLogPath;
        private String m_StrExePath;
        //process temp
        private int m_IdxCurFmtCond;
        private int m_CntFmtCondSet;
        private ET.Application m_EtApp;
        private ET.Range m_rg;
        CondFmtData[] m_CondFmtData;
        private const int m_CntFmtCondLimit = 3;
    }
}

#endif  // #if ENABLE_ET_COM
#endif  // #if ENABLE_EXCEL_COM